package OOPAndMultiThreadArchiveManager.Client.Controllers;

import OOPAndMultiThreadArchiveManager.Client.Models.ApiReceive;
import OOPAndMultiThreadArchiveManager.Client.Models.ApiResponse;
import OOPAndMultiThreadArchiveManager.Client.Tools.PropertiesLoader;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.*;
import java.net.Socket;
import java.util.Vector;

public class HttpController {
    private Socket socket;
    private final static ObjectMapper objectMapper = new ObjectMapper();
    private final static ApiResponse fetchServerError = new ApiResponse(ApiResponse.ApiCode.Failed, "无法连接到服务器");
    private int fileUploadPort = 0;
    private String fileUploadHost = "";
    private int fileDownloadPort = 0;
    private String fileDownloadHost = "";
    private int connectPort = 0;
    private String connectHost = "";

    public HttpController() {
        fileUploadPort = PropertiesLoader.fileUploadPort;
        fileUploadHost = PropertiesLoader.fileUploadHost;
        fileDownloadPort = PropertiesLoader.fileDownloadPort;
        fileDownloadHost = PropertiesLoader.fileDownloadHost;
        connectPort = PropertiesLoader.connectPort;
        connectHost = PropertiesLoader.connectHost;
    }

    public ApiResponse Request(ApiReceive requestData) {
        try {
            socket = new Socket(connectHost, connectPort);
            DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
            outputStream.write(objectMapper.writeValueAsString(requestData).getBytes());
            outputStream.flush();
            socket.shutdownOutput();
            DataInputStream inputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
            String strInputStream = inputStream.readUTF();
            socket.close();
            return objectMapper.readerFor(ApiResponse.class).readValue(strInputStream);
        } catch (IOException e) {
            return fetchServerError;
        }
    }

    public ApiResponse Upload(File file, Vector<Integer> progress) {
        try {
            socket = new Socket(fileUploadHost, fileUploadPort);
            FileInputStream fileInputStream = new FileInputStream(file);
            OutputStream outputStream = socket.getOutputStream();
            int length;
            byte[] outBytes = new byte[1024];
            while ((length = fileInputStream.read(outBytes)) != -1) {
                outputStream.write(outBytes, 0, length);
                progress.set(0, 100 - (int) ( fileInputStream.available() * 1.0 / file.length() * 50 ));
            }
            fileInputStream.close();
            socket.shutdownOutput();

            DataInputStream inputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
            String strInputStream = inputStream.readUTF();
            socket.close();
            return objectMapper.readerFor(ApiResponse.class).readValue(strInputStream);
        } catch (IOException e) {
            return fetchServerError;
        }
    }

    public boolean DownLoad(ApiReceive requestData, File file, Vector<Integer> progress) {
        try {
            socket = new Socket(fileDownloadHost, fileDownloadPort);
            DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
            outputStream.write(objectMapper.writeValueAsString(requestData).getBytes());
            outputStream.flush();
            socket.shutdownOutput();
            progress.set(0, 30);

            InputStream stream = socket.getInputStream();
            if (!file.createNewFile()) {
                return false;
            }
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = stream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, length);
                if(progress.get(0) < 80) progress.set(0, progress.get(0) + 1);
            }
            fileOutputStream.flush();
            fileOutputStream.close();
            socket.close();
            progress.set(0, 100);
            return true;
        } catch (IOException e) {
            try {
                socket.close();
            } catch (IOException ex) {
                return false;
            }
            return false;
        }
    }
}